um-new">
-                            user_id=user_id,
111
-                            coupon_title=coupon.coupon_title,
112
-                            coupon_detail=coupon.coupon_detail,
113
-                            coupon_value=coupon.coupon_value,
114
-                            coupon_image=coupon.coupon_image,
115
-                            active_at=active_at,
116
-                            expire_at=expire_at,
117
-                            coupon_valid_period=coupon.coupon_valid_period,
118
-                            coupon_limit_model_ids=coupon.coupon_limit_model_ids,
119
-                        )
120
-
121
-                user.coupon_expire_at = expire_at
122
-                user.save()
59
+                    UserCouponInfo.objects.create(
60
+                        brand_id=coupon.brand_id,
61
+                        brand_name=coupon.brand_name,
62
+                        coupon_id=coupon_id,
63
+                        user_id=user_id,
64
+                        coupon_title=coupon.coupon_title,
65
+                        coupon_detail=coupon.coupon_detail,
66
+                        coupon_value=coupon.coupon_value,
67
+                        coupon_image=coupon.coupon_image,
68
+                        coupon_from='INTEGRAL_MALL',
69
+                        active_at=tc.utc_datetime(),
70
+                        expire_at=tc.utc_datetime(days=coupon.coupon_valid_period) if coupon.coupon_expire_type == CouponInfo.CHANGED_EXPIRED_TIME else coupon.coupon_expire_at,
71
+                        coupon_valid_period=coupon.coupon_valid_period,
72
+                        coupon_limit_model_ids=coupon.coupon_limit_model_ids,
73
+                        is_coupon_admin_writeoff=coupon.is_coupon_admin_writeoff,
74
+                    )
75
+
76
+                else:
77
+                    # 发放会员权益
78
+                    active_at = tc.utc_datetime()
79
+                    expire_at = tc.utc_datetime(days=365)
80
+
81
+                    rights = RightInfo.objects.filter(is_send_coupon=True, status=True)
82
+                    for right in rights:
83
+                        if user.level == UserInfo.MEMBER_LRC:
84
+                            coupon_id = right.coupon_level1_id
85
+                            coupon_num = right.coupon_level1_num
86
+                        elif user.level == UserInfo.MEMBER_SILVER:
87
+                            coupon_id = right.coupon_level2_id
88
+                            coupon_num = right.coupon_level2_num
89
+                        elif user.level == UserInfo.MEMBER_GOLD:
90
+                            coupon_id = right.coupon_level3_id
91
+                            coupon_num = right.coupon_level3_num
92
+                        elif user.level == UserInfo.MEMBER_WHITE_GOLD:
93
+                            coupon_id = right.coupon_level4_id
94
+                            coupon_num = right.coupon_level4_num
95
+                        elif user.level == UserInfo.MEMBER_BLACK_GOLD:
96
+                            coupon_id = right.coupon_level5_id
97
+                            coupon_num = right.coupon_level5_num
98
+
99
+                        if not coupon_id:
100
+                            continue
101
+
102
+                        try:
103
+                            coupon = CouponInfo.objects.get(coupon_id=coupon_id)
104
+                        except CouponInfo.DoesNotExist:
105
+                            continue
106
+
107
+                        for _ in range(right.coupon_num or coupon_num):
108
+                            UserCouponInfo.objects.create(
109
+                                brand_id=coupon.brand_id,
110
+                                brand_name=coupon.brand_name,
111
+                                coupon_id=coupon_id,
112
+                                user_id=user_id,
113
+                                coupon_title=coupon.coupon_title,
114
+                                coupon_detail=coupon.coupon_detail,
115
+                                coupon_value=coupon.coupon_value,
116
+                                coupon_image=coupon.coupon_image,
117
+                                active_at=active_at,
118
+                                expire_at=expire_at,
119
+                                coupon_valid_period=coupon.coupon_valid_period,
120
+                                coupon_limit_model_ids=coupon.coupon_limit_model_ids,
121
+                            )
122
+
123
+                    user.coupon_expire_at = expire_at
124
+                    user.save()
123 125
 
124 126
             close_old_connections()

+ 52 - 50
commands/management/commands/cpon2.py

@@ -2,6 +2,7 @@
2 2
 
3 3
 import logging
4 4
 
5
+from django.db import transaction
5 6
 from django_six import CompatibilityBaseCommand, close_old_connections
6 7
 from TimeConvert import TimeConvert as tc
7 8
 
@@ -37,58 +38,59 @@ class Command(CompatibilityBaseCommand):
37 38
             brand_id = v.get('brand_id', '')
38 39
             user_id = v.get('user_id', '')
39 40
 
40
-            try:
41
-                user = UserInfo.objects.get(user_id=user_id)
42
-            except UserInfo.DoesNotExist:
43
-                continue
44
-
45
-            active_at = user.coupon_expire_at
46
-            expire_at = tc.utc_datetime(user.coupon_expire_at, days=365)
47
-
48
-            # 发放会员权益
49
-            rights = RightInfo.objects.filter(is_send_coupon=True, is_continue_send_coupon=True, status=True)
50
-            for right in rights:
51
-                if user.level == UserInfo.MEMBER_LRC:
52
-                    coupon_id = right.coupon_level1_id
53
-                    coupon_num = right.coupon_level1_num
54
-                elif user.level == UserInfo.MEMBER_SILVER:
55
-                    coupon_id = right.coupon_level2_id
56
-                    coupon_num = right.coupon_level2_num
57
-                elif user.level == UserInfo.MEMBER_GOLD:
58
-                    coupon_id = right.coupon_level3_id
59
-                    coupon_num = right.coupon_level3_num
60
-                elif user.level == UserInfo.MEMBER_WHITE_GOLD:
61
-                    coupon_id = right.coupon_level4_id
62
-                    coupon_num = right.coupon_level4_num
63
-                elif user.level == UserInfo.MEMBER_BLACK_GOLD:
64
-                    coupon_id = right.coupon_level5_id
65
-                    coupon_num = right.coupon_level5_num
66
-
67
-                if not coupon_id:
68
-                    continue
69
-
41
+            with transaction.atomic():
70 42
                 try:
71
-                    coupon = CouponInfo.objects.get(coupon_id=coupon_id)
72
-                except CouponInfo.DoesNotExist:
43
+                    user = UserInfo.objects.get(user_id=user_id)
44
+                except UserInfo.DoesNotExist:
73 45
                     continue
74 46
 
75
-                for _ in range(right.coupon_num or coupon_num):
76
-                    UserCouponInfo.objects.create(
77
-                        brand_id=coupon.brand_id,
78
-                        brand_name=coupon.brand_name,
79
-                        coupon_id=coupon_id,
80
-                        user_id=user_id,
81
-                        coupon_title=coupon.coupon_title,
82
-                        coupon_detail=coupon.coupon_detail,
83
-                        coupon_value=coupon.coupon_value,
84
-                        coupon_image=coupon.coupon_image,
85
-                        active_at=active_at,
86
-                        expire_at=expire_at,
87
-                        coupon_valid_period=coupon.coupon_valid_period,
88
-                        coupon_limit_model_ids=coupon.coupon_limit_model_ids,
89
-                    )
90
-
91
-            user.coupon_expire_at = expire_at
92
-            user.save()
47
+                active_at = user.coupon_expire_at
48
+                expire_at = tc.utc_datetime(user.coupon_expire_at, days=365)
49
+
50
+                # 发放会员权益
51
+                rights = RightInfo.objects.filter(is_send_coupon=True, is_continue_send_coupon=True, status=True)
52
+                for right in rights:
53
+                    if user.level == UserInfo.MEMBER_LRC:
54
+                        coupon_id = right.coupon_level1_id
55
+                        coupon_num = right.coupon_level1_num
56
+                    elif user.level == UserInfo.MEMBER_SILVER:
57
+                        coupon_id = right.coupon_level2_id
58
+                        coupon_num = right.coupon_level2_num
59
+                    elif user.level == UserInfo.MEMBER_GOLD:
60
+                        coupon_id = right.coupon_level3_id
61
+                        coupon_num = right.coupon_level3_num
62
+                    elif user.level == UserInfo.MEMBER_WHITE_GOLD:
63
+                        coupon_id = right.coupon_level4_id
64
+                        coupon_num = right.coupon_level4_num
65
+                    elif user.level == UserInfo.MEMBER_BLACK_GOLD:
66
+                        coupon_id = right.coupon_level5_id
67
+                        coupon_num = right.coupon_level5_num
68
+
69
+                    if not coupon_id:
70
+                        continue
71
+
72
+                    try:
73
+                        coupon = CouponInfo.objects.get(coupon_id=coupon_id)
74
+                    except CouponInfo.DoesNotExist:
75
+                        continue
76
+
77
+                    for _ in range(right.coupon_num or coupon_num):
78
+                        UserCouponInfo.objects.create(
79
+                            brand_id=coupon.brand_id,
80
+                            brand_name=coupon.brand_name,
81
+                            coupon_id=coupon_id,
82
+                            user_id=user_id,
83
+                            coupon_title=coupon.coupon_title,
84
+                            coupon_detail=coupon.coupon_detail,
85
+                            coupon_value=coupon.coupon_value,
86
+                            coupon_image=coupon.coupon_image,
87
+                            active_at=active_at,
88
+                            expire_at=expire_at,
89
+                            coupon_valid_period=coupon.coupon_valid_period,
90
+                            coupon_limit_model_ids=coupon.coupon_limit_model_ids,
91
+                        )
92
+
93
+                user.coupon_expire_at = expire_at
94
+                user.save()
93 95
 
94 96
             close_old_connections()

+ 1 - 1
member/admin.py

@@ -110,7 +110,7 @@ class MemberActivityContributionWelfareInfoAdmin(admin.ModelAdmin):
110 110
 
111 111
 
112 112
 class MemberActivityContributionWelfareUnlockingInfoAdmin(admin.ModelAdmin):
113
-    list_display = ('unlocking_id', 'admin_id', 'user_id', 'activity_id', 'contribution_id', 'welfare_id', 'name', 'phone', 'address', 'tracking_number', 'is_handled', 'status', 'created_at', 'updated_at')
113
+    list_display = ('unlocking_id', 'admin_id', 'user_id', 'activity_id', 'contribution_id', 'welfare_id', 'welfare_type', 'welfare_value', 'name', 'phone', 'address', 'tracking_number', 'is_handled', 'status', 'created_at', 'updated_at')
114 114
     list_filter = ('admin_id', 'activity_id', 'welfare_id', 'is_handled', 'status')
115 115
 
116 116
 

+ 19 - 0
member/migrations/0046_memberactivitycontributionwelfareunlockinginfo_welfare_value.py

@@ -0,0 +1,19 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 3.2.16 on 2022-10-27 10:38
3
+
4
+from django.db import migrations, models
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('member', '0045_auto_20221026_2102'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='memberactivitycontributionwelfareunlockinginfo',
16
+            name='welfare_value',
17
+            field=models.IntegerField(default=0, help_text='福利数量', verbose_name='welfare_value'),
18
+        ),
19
+    ]

+ 19 - 0
member/migrations/0047_memberactivitycontributionwelfareunlockinginfo_welfare_type.py

@@ -0,0 +1,19 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 3.2.16 on 2022-10-27 10:46
3
+
4
+from django.db import migrations, models
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    dependencies = [
10
+        ('member', '0046_memberactivitycontributionwelfareunlockinginfo_welfare_value'),
11
+    ]
12
+
13
+    operations = [
14
+        migrations.AddField(
15
+            model_name='memberactivitycontributionwelfareunlockinginfo',
16
+            name='welfare_type',
17
+            field=models.IntegerField(choices=[(0, '实物'), (1, '积分'), (2, '虚拟')], db_index=True, default=0, help_text='福利类型', verbose_name='welfare_type'),
18
+        ),
19
+    ]

+ 3 - 0
member/models.py

@@ -795,6 +795,7 @@ class MemberActivityContributionWelfareInfo(BaseModelMixin, BrandInfoMixin):
795 795
 
796 796
 
797 797
 class MemberActivityContributionWelfareUnlockingInfo(BaseModelMixin, BrandInfoMixin):
798
+    WELFARE_INTEGRAL = 1
798 799
     WELFARE_TYPE = (
799 800
         (0, u'实物'),
800 801
         (1, u'积分'),
@@ -811,6 +812,8 @@ class MemberActivityContributionWelfareUnlockingInfo(BaseModelMixin, BrandInfoMi
811 812
     contribution_id = models.CharField(_(u'contribution_id'), max_length=32, blank=True, null=True, help_text=u'投稿唯一标识', db_index=True)
812 813
 
813 814
     welfare_id = models.CharField(_(u'welfare_id'), max_length=32, blank=True, null=True, help_text=u'福利唯一标识', db_index=True)
815
+    welfare_type = models.IntegerField(_(u'welfare_type'), choices=WELFARE_TYPE, default=0, help_text=u'福利类型', db_index=True)
816
+    welfare_value = models.IntegerField(_(u'welfare_value'), default=0, help_text=_(u'福利数量'))
814 817
 
815 818
     name = models.CharField(_(u'name'), max_length=255, blank=True, null=True, help_text=u'姓名')
816 819
     phone = models.CharField(_(u'phone'), max_length=255, blank=True, null=True, help_text=u'电话')

+ 6 - 5
miniapp/views.py

@@ -318,19 +318,20 @@ def user_integral_add(request):
318 318
         return response(ProductBrandStatusCode.BRAND_NOT_MATCH)
319 319
 
320 320
     try:
321
-        user = UserInfo.objects.get(user_id=user_id, status=True)
321
+        user = UserInfo.objects.select_for_update().get(user_id=user_id, status=True)
322 322
     except UserInfo.DoesNotExist:
323 323
         return response(UserStatusCode.USER_NOT_FOUND)
324 324
 
325
+    user.integral += integral
326
+    user.save()
327
+
325 328
     UserIntegralIncomeExpensesInfo.objects.create(
326 329
         brand_id=brand_id,
327 330
         user_id=user_id,
328 331
         integral_from=UserIntegralIncomeExpensesInfo.CONTRIBUTE,
329 332
         integral=integral,
330
-        remark=remark
333
+        final_integral=user.integral,
334
+        remark=remark,
331 335
     )
332 336
 
333
-    user.integral += integral
334
-    user.save()
335
-
336 337
     return response(200, 'Add User Integral Success', u'添加用户投稿积分成功')

+ 74 - 73
utils/error/errno_utils.py

@@ -8,6 +8,78 @@ class ParamStatusCode(BaseStatusCode):
8 8
     PARAM_NOT_FOUND = StatusCodeField(400000, 'Param Not Found', description=u'参数不存在')
9 9
 
10 10
 
11
+class PermissionStatusCode(BaseStatusCode):
12
+    """ 4099xx 权限相关错误码 """
13
+    PERMISSION_DENIED = StatusCodeField(409900, 'Permission Denied', description=u'权限不足')
14
+
15
+
16
+class AdministratorStatusCode(BaseStatusCode):
17
+    """ 操作员相关错误码 4002xx """
18
+    ADMINISTRATOR_NOT_FOUND = StatusCodeField(400201, 'Administrator Not Found', description=u'管理员不存在')
19
+    ADMINISTRATOR_PERMISSION_DENIED = StatusCodeField(508002, 'Administrator Permission Denied', description=u'管理员权限不足')
20
+
21
+    # 密码
22
+    ADMINISTRATOR_PASSWORD_ERROR = StatusCodeField(400202, 'Administrator Password Error', description=u'管理员密码错误')
23
+    # 手机号
24
+    ADMINISTRATOR_PHONE_ALREADY_EXISTS = StatusCodeField(400205, 'Administrator Phone Already Exists', description=u'管理员手机号已经存在')
25
+    # 状态
26
+    ADMINISTRATOR_NOT_ACTIVATED = StatusCodeField(400215, 'Administrator Not Activated', description=u'管理员未激活')
27
+    ADMINISTRATOR_HAS_DISABLED = StatusCodeField(400216, 'Administrator Has Disabled', description=u'管理员已禁用')
28
+    ADMINISTRATOR_HAS_DELETED = StatusCodeField(400217, 'Administrator Has Deleted', description=u'管理员已删除')
29
+    # 管理员
30
+    MAINTENANCE_NOT_FOUND = StatusCodeField(400251, 'Maintenance Not Found', description=u'核销员不存在')
31
+
32
+
33
+class OperatorStatusCode(BaseStatusCode):
34
+    """ 操作员相关错误码 4003xx """
35
+    OPERATOR_NOT_FOUND = StatusCodeField(400301, 'Operator Not Found', description=u'操作员不存在')
36
+    # 密码
37
+    OPERATOR_PASSWORD_ERROR = StatusCodeField(400302, 'Operator Password Error', description=u'操作员密码错误')
38
+    # 手机号
39
+    OPERATOR_PHONE_ALREADY_EXISTS = StatusCodeField(400305, 'Operator Phone Already Exists', description=u'操作员手机号已经存在')
40
+    # 状态
41
+    OPERATOR_NOT_ACTIVATED = StatusCodeField(400315, 'Operator Not Activated', description=u'操作员未激活')
42
+    OPERATOR_HAS_DISABLED = StatusCodeField(400316, 'Operator Has Disabled', description=u'操作员已禁用')
43
+    OPERATOR_HAS_DELETED = StatusCodeField(400317, 'Operator Has Deleted', description=u'操作员已删除')
44
+
45
+
46
+class UserStatusCode(BaseStatusCode):
47
+    """ 用户相关错误码  4005xx """
48
+    USER_NOT_FOUND = StatusCodeField(400501, 'User Not Found', description=u'用户不存在')
49
+    USER_PASSWORD_ERROR = StatusCodeField(400502, 'User Password Error', description=u'用户密码错误')
50
+    USERNAME_HAS_REGISTERED = StatusCodeField(400503, 'Username Has Registered', description=u'用户名已注册')
51
+    # 游客
52
+    GUEST_NOT_ALLOWED = StatusCodeField(400511, 'Guest Not ALLOWED', description=u'游客登录未开启')
53
+    # 身份
54
+    USER_NOT_LENSMAN = StatusCodeField(400521, 'User Not Lensman', description=u'用户非摄影师')
55
+    USER_NOT_TOURGUIDE = StatusCodeField(400522, 'User Not Tourguide', description=u'用户非导游')
56
+
57
+
58
+class PhoneStatusCode(BaseStatusCode):
59
+    """ 手机相关错误码  4006xx """
60
+    PHONE_NOT_FOUND = StatusCodeField(400601, 'Phone Not Found', description=u'手机不存在')
61
+
62
+
63
+class WechatStatusCode(BaseStatusCode):
64
+    """ 微信相关错误码  4007xx """
65
+    WECHAT_NOT_FOUND = StatusCodeField(400701, 'Wechat Not Found', description=u'微信不存在')
66
+    UNIONID_NOT_FOUND = StatusCodeField(400702, 'Unionid Not Found', description=u'微信 UNIONID 不存在')
67
+    OPENID_NOT_FOUND = StatusCodeField(400703, 'OPENID Not Found', description=u'微信 OPENID 不存在')
68
+
69
+
70
+class ScreenStatusCode(BaseStatusCode):
71
+    """ 群组/团相关错误码 4030xx """
72
+    QRCODE_NOT_SCAN = StatusCodeField(403001, 'QRCode Not Scan', description=u'二维码未扫描')
73
+
74
+
75
+class CouponStatusCode(BaseStatusCode):
76
+    """ 4050xx 优惠劵相关错误码 """
77
+    COUPON_NOT_FOUND = StatusCodeField(405001, 'Coupon Not Found', description=u'劵不存在')
78
+    COUPON_EXPIRED = StatusCodeField(405002, 'Coupon Expired', description=u'劵已过期')
79
+    COUPON_PERMISSION_DENIED = StatusCodeField(405003, 'Permission Denied', description=u'核销劵权限不足')
80
+    COUPON_HAS_USED = StatusCodeField(405004, 'Coupon Has Used', description=u'劵已核销')
81
+
82
+
11 83
 class SaleclerkStatusCode(BaseStatusCode):
12 84
     """ 店员相关错误码 5001xx """
13 85
     CLERK_NOT_FOUND = StatusCodeField(500101, 'Clerk Not Found', description=u'店员不存在')
@@ -107,7 +179,8 @@ class MemberActivityContributionWelfareStatusCode(BaseStatusCode):
107 179
 
108 180
 class MemberActivityContributionWelfareUnblockingStatusCode(BaseStatusCode):
109 181
     """ 会员活动投稿福利相关错误码 5039xx """
110
-    ACTIVITY_CONTRIBUTION_WELFARE_UNBLOCKING_NOT_FOUND = StatusCodeField(503999, 'Activity Contribution Welfare Unblocking Not Found', description=u'活动投稿福利解锁不存在')
182
+    ACTIVITY_CONTRIBUTION_WELFARE_UNBLOCKING_NOT_FOUND = StatusCodeField(503901, 'Activity Contribution Welfare Unblocking Not Found', description=u'活动投稿福利解锁不存在')
183
+    ACTIVITY_CONTRIBUTION_WELFARE_UNBLOCKING_HAS_HANDLED = StatusCodeField(503902, 'Activity Contribution Welfare Unblocking Has Handled', description=u'活动投稿福利解锁已处理')
111 184
 
112 185
 
113 186
 class MemberCouponStatusCode(BaseStatusCode):
@@ -138,75 +211,3 @@ class MaintenanceStatusCode(BaseStatusCode):
138 211
     """ 维修相关错误码 5080xx """
139 212
     MAINTENACE_NOT_FOUND = StatusCodeField(508001, 'Maintenance Not Found', description=u'维修不存在')
140 213
     MAINTENACE_PERMISSION_DENIED = StatusCodeField(508002, 'Maintenance Permission Denied', description=u'维修权限不足')
141
-
142
-
143
-class AdministratorStatusCode(BaseStatusCode):
144
-    """ 操作员相关错误码 4002xx """
145
-    ADMINISTRATOR_NOT_FOUND = StatusCodeField(400201, 'Administrator Not Found', description=u'管理员不存在')
146
-    ADMINISTRATOR_PERMISSION_DENIED = StatusCodeField(508002, 'Administrator Permission Denied', description=u'管理员权限不足')
147
-
148
-    # 密码
149
-    ADMINISTRATOR_PASSWORD_ERROR = StatusCodeField(400202, 'Administrator Password Error', description=u'管理员密码错误')
150
-    # 手机号
151
-    ADMINISTRATOR_PHONE_ALREADY_EXISTS = StatusCodeField(400205, 'Administrator Phone Already Exists', description=u'管理员手机号已经存在')
152
-    # 状态
153
-    ADMINISTRATOR_NOT_ACTIVATED = StatusCodeField(400215, 'Administrator Not Activated', description=u'管理员未激活')
154
-    ADMINISTRATOR_HAS_DISABLED = StatusCodeField(400216, 'Administrator Has Disabled', description=u'管理员已禁用')
155
-    ADMINISTRATOR_HAS_DELETED = StatusCodeField(400217, 'Administrator Has Deleted', description=u'管理员已删除')
156
-    # 管理员
157
-    MAINTENANCE_NOT_FOUND = StatusCodeField(400251, 'Maintenance Not Found', description=u'核销员不存在')
158
-
159
-
160
-class OperatorStatusCode(BaseStatusCode):
161
-    """ 操作员相关错误码 4003xx """
162
-    OPERATOR_NOT_FOUND = StatusCodeField(400301, 'Operator Not Found', description=u'操作员不存在')
163
-    # 密码
164
-    OPERATOR_PASSWORD_ERROR = StatusCodeField(400302, 'Operator Password Error', description=u'操作员密码错误')
165
-    # 手机号
166
-    OPERATOR_PHONE_ALREADY_EXISTS = StatusCodeField(400305, 'Operator Phone Already Exists', description=u'操作员手机号已经存在')
167
-    # 状态
168
-    OPERATOR_NOT_ACTIVATED = StatusCodeField(400315, 'Operator Not Activated', description=u'操作员未激活')
169
-    OPERATOR_HAS_DISABLED = StatusCodeField(400316, 'Operator Has Disabled', description=u'操作员已禁用')
170
-    OPERATOR_HAS_DELETED = StatusCodeField(400317, 'Operator Has Deleted', description=u'操作员已删除')
171
-
172
-
173
-class UserStatusCode(BaseStatusCode):
174
-    """ 用户相关错误码  4005xx """
175
-    USER_NOT_FOUND = StatusCodeField(400501, 'User Not Found', description=u'用户不存在')
176
-    USER_PASSWORD_ERROR = StatusCodeField(400502, 'User Password Error', description=u'用户密码错误')
177
-    USERNAME_HAS_REGISTERED = StatusCodeField(400503, 'Username Has Registered', description=u'用户名已注册')
178
-    # 游客
179
-    GUEST_NOT_ALLOWED = StatusCodeField(400511, 'Guest Not ALLOWED', description=u'游客登录未开启')
180
-    # 身份
181
-    USER_NOT_LENSMAN = StatusCodeField(400521, 'User Not Lensman', description=u'用户非摄影师')
182
-    USER_NOT_TOURGUIDE = StatusCodeField(400522, 'User Not Tourguide', description=u'用户非导游')
183
-
184
-
185
-class PhoneStatusCode(BaseStatusCode):
186
-    """ 手机相关错误码  4006xx """
187
-    PHONE_NOT_FOUND = StatusCodeField(400601, 'Phone Not Found', description=u'手机不存在')
188
-
189
-
190
-class WechatStatusCode(BaseStatusCode):
191
-    """ 微信相关错误码  4007xx """
192
-    WECHAT_NOT_FOUND = StatusCodeField(400701, 'Wechat Not Found', description=u'微信不存在')
193
-    UNIONID_NOT_FOUND = StatusCodeField(400702, 'Unionid Not Found', description=u'微信 UNIONID 不存在')
194
-    OPENID_NOT_FOUND = StatusCodeField(400703, 'OPENID Not Found', description=u'微信 OPENID 不存在')
195
-
196
-
197
-class ScreenStatusCode(BaseStatusCode):
198
-    """ 群组/团相关错误码 4030xx """
199
-    QRCODE_NOT_SCAN = StatusCodeField(403001, 'QRCode Not Scan', description=u'二维码未扫描')
200
-
201
-
202
-class PermissionStatusCode(BaseStatusCode):
203
-    """ 4099xx 权限相关错误码 """
204
-    PERMISSION_DENIED = StatusCodeField(409900, 'Permission Denied', description=u'权限不足')
205
-
206
-
207
-class CouponStatusCode(BaseStatusCode):
208
-    """ 4050xx 优惠劵相关错误码 """
209
-    COUPON_NOT_FOUND = StatusCodeField(405001, 'Coupon Not Found', description=u'劵不存在')
210
-    COUPON_EXPIRED = StatusCodeField(405002, 'Coupon Expired', description=u'劵已过期')
211
-    COUPON_PERMISSION_DENIED = StatusCodeField(405003, 'Permission Denied', description=u'核销劵权限不足')
212
-    COUPON_HAS_USED = StatusCodeField(405004, 'Coupon Has Used', description=u'劵已核销')

Guideline Login Error · 88c914df41 - Gogs: Go Git Service

Guideline Login Error

Brightcells 7 years ago
parent
commit
88c914df41

+ 1 - 1
account/admin.py

@@ -8,7 +8,7 @@ from mch.models import ConsumeInfoSubmitLogInfo
8 8
 
9 9
 
10 10
 class UserInfoAdmin(ChangeOnlyModelAdmin, admin.ModelAdmin):
11
-    list_display = ('user_id', 'username', 'unionid', 'openid', 'openid_miniapp', 'name', 'sex', 'nickname', 'phone', 'location', 'balance', 'user_status', 'test_user', 'status', 'created_at', 'updated_at')
11
+    list_display = ('user_id', 'unionid', 'openid', 'nickname', 'phone', 'location', 'balance', 'user_status', 'test_user', 'status', 'created_at', 'updated_at')
12 12
     list_filter = ('test_user', 'sex', 'user_status', 'status')
13 13
     readonly_fields = ('user_id', )
14 14
     search_fields = ('user_id', 'username', 'unionid', 'openid', 'openid_miniapp', 'name', 'phone', 'location')

+ 6 - 1
api/urls.py

@@ -14,7 +14,7 @@ from group import views as group_views
14 14
 from message import views as message_views
15 15
 from miniapp import views as mini_views
16 16
 from operation import views as op_views
17
-from page import oauth_views, sale_views
17
+from page import oauth_views, sale_views, screen_views
18 18
 from pay import views as pay_views
19 19
 from photo import views as photo_views
20 20
 from server import server_views
@@ -269,3 +269,8 @@ urlpatterns += [
269 269
     url(r'^clerk/update$', clerk_views.clerk_update, name='clerk_update'),
270 270
     url(r'^clerk/list$', clerk_views.clerk_list, name='clerk_list'),
271 271
 ]
272
+
273
+urlpatterns += [
274
+    url(r'^screen/admin/loginqr$', screen_views.screen_admin_loginqr, name='screen_admin_loginqr'),
275
+    url(r'^screen/admin/loginrst$', screen_views.screen_admin_loginrst, name='screen_admin_loginrst'),
276
+]

+ 0 - 0
guideline/__init__.py


+ 15 - 0
guideline/admin.py

@@ -0,0 +1,15 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib import admin
4
+from django_admin import ChangeOnlyModelAdmin, ReadOnlyModelAdmin
5
+
6
+from guideline.models import ScreenAdminInfo
7
+
8
+
9
+class ScreenAdminInfoAdmin(ChangeOnlyModelAdmin, admin.ModelAdmin):
10
+    list_display = ('admin_id', 'unionid', 'openid', 'name', 'sex', 'nickname', 'phone', 'location', 'status', 'created_at', 'updated_at')
11
+    readonly_fields = ('admin_id',)
12
+    search_fields = ('admin_id', 'unionid', 'openid', 'name', 'phone', 'location')
13
+
14
+
15
+admin.site.register(ScreenAdminInfo, ScreenAdminInfoAdmin)

+ 8 - 0
guideline/apps.py

@@ -0,0 +1,8 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.apps import AppConfig
5
+
6
+
7
+class GuidelineConfig(AppConfig):
8
+    name = 'guideline'

+ 48 - 0
guideline/migrations/0001_initial.py

@@ -0,0 +1,48 @@
1
+# -*- coding: utf-8 -*-
2
+# Generated by Django 1.11.16 on 2018-11-14 20:44
3
+from __future__ import unicode_literals
4
+
5
+from django.db import migrations, models
6
+
7
+
8
+class Migration(migrations.Migration):
9
+
10
+    initial = True
11
+
12
+    dependencies = [
13
+    ]
14
+
15
+    operations = [
16
+        migrations.CreateModel(
17
+            name='ScreenAdminInfo',
18
+            fields=[
19
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20
+                ('status', models.BooleanField(db_index=True, default=True, help_text='Status', verbose_name='status')),
21
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')),
22
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')),
23
+                ('admin_id', models.CharField(blank=True, db_index=True, help_text='\u5927\u5c4f\u7ba1\u7406\u5458\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, unique=True, verbose_name='admin_id')),
24
+                ('unionid', models.CharField(blank=True, db_index=True, help_text='\u5fae\u4fe1 Union ID', max_length=32, null=True, verbose_name='unionid')),
25
+                ('openid', models.CharField(blank=True, db_index=True, help_text='\u5fae\u4fe1 Open ID', max_length=32, null=True, verbose_name='openid')),
26
+                ('name', models.CharField(blank=True, help_text='\u7528\u6237\u59d3\u540d', max_length=8, null=True, verbose_name='name')),
27
+                ('sex', models.IntegerField(choices=[(1, '\u7537'), (0, '\u5973')], default=1, help_text='\u7528\u6237\u6027\u522b', verbose_name='sex')),
28
+                ('nickname', models.CharField(blank=True, help_text='\u7528\u6237\u6635\u79f0', max_length=255, null=True, verbose_name='nickname')),
29
+                ('avatar', models.CharField(blank=True, help_text='\u7528\u6237\u5934\u50cf', max_length=255, null=True, verbose_name='avatar')),
30
+                ('phone', models.CharField(blank=True, db_index=True, help_text='\u7528\u6237\u7535\u8bdd', max_length=11, null=True, verbose_name='phone')),
31
+                ('country', models.CharField(blank=True, help_text='\u7528\u6237\u56fd\u5bb6', max_length=16, null=True, verbose_name='country')),
32
+                ('province', models.CharField(blank=True, help_text='\u7528\u6237\u7701\u4efd', max_length=16, null=True, verbose_name='province')),
33
+                ('city', models.CharField(blank=True, help_text='\u7528\u6237\u57ce\u5e02', max_length=16, null=True, verbose_name='city')),
34
+                ('location', models.CharField(blank=True, help_text='\u7528\u6237\u5730\u5740', max_length=255, null=True, verbose_name='location')),
35
+                ('brand_id', models.CharField(blank=True, db_index=True, help_text='\u54c1\u724c\u552f\u4e00\u6807\u8bc6', max_length=32, null=True, verbose_name='brand_id')),
36
+                ('brand_name', models.CharField(blank=True, help_text='\u54c1\u724c\u540d\u79f0', max_length=255, null=True, verbose_name='brand_name')),
37
+                ('user_status', models.IntegerField(choices=[(1, '\u5df2\u6fc0\u6d3b'), (2, '\u5df2\u7981\u7528'), (3, '\u5df2\u5220\u9664')], db_index=True, default=1, help_text='\u7ba1\u7406\u5458\u72b6\u6001', verbose_name='user_status')),
38
+            ],
39
+            options={
40
+                'verbose_name': 'ScreenAdminInfo',
41
+                'verbose_name_plural': 'ScreenAdminInfo',
42
+            },
43
+        ),
44
+        migrations.AlterUniqueTogether(
45
+            name='screenadmininfo',
46
+            unique_together=set([('brand_id', 'unionid', 'openid')]),
47
+        ),
48
+    ]

+ 0 - 0
guideline/migrations/__init__.py


+ 63 - 0
guideline/models.py

@@ -0,0 +1,63 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.db import models
4
+from django.utils.translation import ugettext_lazy as _
5
+from django_models_ext import BaseModelMixin
6
+
7
+
8
+class ScreenAdminInfo(BaseModelMixin):
9
+    MALE = 1
10
+    FEMALE = 0
11
+
12
+    SEX_TYPE_TUPLE = (
13
+        (MALE, u'男'),
14
+        (FEMALE, u'女'),
15
+    )
16
+
17
+    ACTIVATED = 1
18
+    DISABLED = 2
19
+    DELETED = 3
20
+
21
+    USER_STATUS_TUPLE = (
22
+        (ACTIVATED, u'已激活'),
23
+        (DISABLED, u'已禁用'),
24
+        (DELETED, u'已删除'),
25
+    )
26
+
27
+    admin_id = models.CharField(_(u'admin_id'), max_length=32, blank=True, null=True, help_text=u'大屏管理员唯一标识', db_index=True, unique=True)
28
+
29
+    unionid = models.CharField(_(u'unionid'), max_length=32, blank=True, null=True, help_text=u'微信 Union ID', db_index=True)
30
+    openid = models.CharField(_(u'openid'), max_length=32, blank=True, null=True, help_text=u'微信 Open ID', db_index=True)
31
+
32
+    name = models.CharField(_(u'name'), max_length=8, blank=True, null=True, help_text=u'用户姓名')
33
+    sex = models.IntegerField(_(u'sex'), choices=SEX_TYPE_TUPLE, default=MALE, help_text=u'用户性别')
34
+    nickname = models.CharField(_(u'nickname'), max_length=255, blank=True, null=True, help_text=u'用户昵称')
35
+    avatar = models.CharField(_(u'avatar'), max_length=255, blank=True, null=True, help_text=u'用户头像')
36
+    phone = models.CharField(_(u'phone'), max_length=11, blank=True, null=True, help_text=u'用户电话', db_index=True)
37
+    country = models.CharField(_(u'country'), max_length=16, blank=True, null=True, help_text=u'用户国家')
38
+    province = models.CharField(_(u'province'), max_length=16, blank=True, null=True, help_text=u'用户省份')
39
+    city = models.CharField(_(u'city'), max_length=16, blank=True, null=True, help_text=u'用户城市')
40
+    location = models.CharField(_(u'location'), max_length=255, blank=True, null=True, help_text=u'用户地址')
41
+
42
+    brand_id = models.CharField(_(u'brand_id'), max_length=32, blank=True, null=True, help_text=u'品牌唯一标识', db_index=True)
43
+    brand_name = models.CharField(_(u'brand_name'), max_length=255, blank=True, null=True, help_text=u'品牌名称')
44
+
45
+    user_status = models.IntegerField(_(u'user_status'), choices=USER_STATUS_TUPLE, default=ACTIVATED, help_text=u'管理员状态', db_index=True)
46
+
47
+    class Meta:
48
+        verbose_name = _(u'ScreenAdminInfo')
49
+        verbose_name_plural = _(u'ScreenAdminInfo')
50
+
51
+        unique_together = (
52
+            ('brand_id', 'unionid', 'openid'),
53
+        )
54
+
55
+    def __unicode__(self):
56
+        return unicode(self.pk)
57
+
58
+    @property
59
+    def data(self):
60
+        return {
61
+            'nickname': self.nickname,
62
+            'avatar': self.avatar,
63
+        }

+ 7 - 0
guideline/tests.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.test import TestCase
5
+
6
+
7
+# Create your tests here.

+ 7 - 0
guideline/views.py

@@ -0,0 +1,7 @@
1
+# -*- coding: utf-8 -*-
2
+from __future__ import unicode_literals
3
+
4
+from django.shortcuts import render
5
+
6
+
7
+# Create your views here.

+ 27 - 0
kodo/local_settings_dev.py

@@ -0,0 +1,27 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import os
4
+
5
+
6
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
7
+PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
8
+
9
+TEMPLATES = [
10
+    {
11
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
12
+        'DIRS': [os.path.join(BASE_DIR, 'templates')],
13
+        # 'APP_DIRS': True,
14
+        'OPTIONS': {
15
+            'context_processors': [
16
+                'django.template.context_processors.debug',
17
+                'django.template.context_processors.request',
18
+                'django.contrib.auth.context_processors.auth',
19
+                'django.contrib.messages.context_processors.messages',
20
+            ],
21
+            'loaders': [
22
+                'django.template.loaders.filesystem.Loader',
23
+                'django.template.loaders.app_directories.Loader',
24
+            ],
25
+        },
26
+    },
27
+]

+ 27 - 0
kodo/local_settings_dev_bak.py

@@ -0,0 +1,27 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import os
4
+
5
+
6
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
7
+PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
8
+
9
+TEMPLATES = [
10
+    {
11
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
12
+        'DIRS': [os.path.join(BASE_DIR, 'templates')],
13
+        # 'APP_DIRS': True,
14
+        'OPTIONS': {
15
+            'context_processors': [
16
+                'django.template.context_processors.debug',
17
+                'django.template.context_processors.request',
18
+                'django.contrib.auth.context_processors.auth',
19
+                'django.contrib.messages.context_processors.messages',
20
+            ],
21
+            'loaders': [
22
+                'django.template.loaders.filesystem.Loader',
23
+                'django.template.loaders.app_directories.Loader',
24
+            ],
25
+        },
26
+    },
27
+]

+ 10 - 0
kodo/settings.py

@@ -54,6 +54,7 @@ INSTALLED_APPS = (
54 54
     'box',
55 55
     'commands',
56 56
     'group',
57
+    'guideline',
57 58
     'integral',
58 59
     'logs',
59 60
     'mch',
@@ -390,11 +391,20 @@ KODO_DEFAULT_BRAND_NAME = ''
390 391
 KODO_DEFAULT_BRAND_DOMAIN = ''
391 392
 
392 393
 KODO_CLERK_AUTH_URL = 'http://pai.ai/w/o?r=http%3A%2F%2Fkodo.xfoto.com.cn%2Fp%2Fclerk%3Fbrand_id%3D{0}'
394
+KODO_SCREEN_AUTH_URL = 'http://pai.ai/w/o?r=http%3A%2F%2Fkodo.xfoto.com.cn%2Fp%2Fscreen%2Fadmin%2Foauth%3Fbrand_id%3D{0}'
395
+KODO_SCREEN_LOGIN_URL = 'http://pai.ai/w/o?s=snsapi_base&r=http%3A%2F%2Fkodo.xfoto.com.cn%2Fp%2Fscreen%2Fadmin%2Flogin/%3Fbrand_id%3D{0}%26token%3D{1}'
393 396
 
394 397
 # 经纬度
395 398
 GIS_2_ADMINISTRATIVE_DIVISION = 'http://116.196.105.215:1234/gis?auth_user=freevip&latitude={0}&longitude={1}'
396 399
 PHONE_2_ADMINISTRATIVE_DIVISION = 'https://www.baifubao.com/callback?cmd=1059&callback=phone&phone={0}'
397 400
 
401
+# 开发调试相关配置
402
+if DEBUG:
403
+    try:
404
+        from local_settings_dev import *
405
+    except ImportError:
406
+        pass
407
+
398 408
 try:
399 409
     from local_settings import *
400 410
 except ImportError:

+ 79 - 0
page/screen_views.py

@@ -0,0 +1,79 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import shortuuid
4
+from django.conf import settings
5
+from django_response import response
6
+from json_render import json_render
7
+
8
+from guideline.models import ScreenAdminInfo
9
+from utils.error.errno_utils import PermissionStatusCode
10
+from utils.redis.connect import r
11
+from utils.redis.rkeys import KODO_SCREEN_ADMIN_LOGIN
12
+
13
+
14
+def screen_admin_oauthqr(request):
15
+    brand_id = request.GET.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
16
+
17
+    return json_render(request, 'page/screen_admin_oauth_qrcode.html', unjsondumpsdict={
18
+        'qr': settings.KODO_SCREEN_AUTH_URL.format(brand_id)
19
+    })
20
+
21
+
22
+def screen_admin_oauth(request):
23
+    brand_id = request.GET.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
24
+    unionid = request.GET.get('unionid', '')
25
+    openid = request.GET.get('openid', '')
26
+
27
+    ScreenAdminInfo.objects.update_or_create(brand_id=brand_id, unionid=unionid, openid=openid, defaults={
28
+        'nickname': request.GET.get('nickname', ''),
29
+        'avatar': request.GET.get('avatar', ''),
30
+        'user_status': ScreenAdminInfo.ACTIVATED,
31
+    })
32
+
33
+    return json_render(request, 'page/screen_admin_oauth_success.html', unjsondumpsdict={
34
+    })
35
+
36
+
37
+def screen_admin_loginqr(request):
38
+    brand_id = request.GET.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
39
+
40
+    token = shortuuid.uuid()
41
+
42
+    return response(200, {
43
+        'qr': settings.KODO_SCREEN_LOGIN_URL.format(brand_id, token),
44
+        'token': token,
45
+    })
46
+
47
+
48
+def screen_admin_login(request):
49
+    brand_id = request.GET.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
50
+    unionid = request.GET.get('unionid', '')
51
+    openid = request.GET.get('openid', '')
52
+    token = request.GET.get('token', '')
53
+
54
+    try:
55
+        admin = ScreenAdminInfo.objects.get(unionid=unionid, user_status=ScreenAdminInfo.ACTIVATED)
56
+    except ScreenAdminInfo.DoesNotExist:
57
+        return json_render(request, 'page/screen_admin_login_fail.html', unjsondumpsdict={
58
+        })
59
+
60
+    r.setex(KODO_SCREEN_ADMIN_LOGIN % (brand_id, token), r.REDIS_EXPIRED_HALF_HOUR, unionid)
61
+
62
+    return json_render(request, 'page/screen_admin_login_success.html', unjsondumpsdict={
63
+    })
64
+
65
+
66
+def screen_admin_loginrst(request):
67
+    brand_id = request.GET.get('brand_id', settings.KODO_DEFAULT_BRAND_ID)
68
+    token = request.GET.get('token', '')
69
+
70
+    unionid = r.get(KODO_SCREEN_ADMIN_LOGIN % (brand_id, token))
71
+
72
+    try:
73
+        admin = ScreenAdminInfo.objects.get(unionid=unionid, user_status=ScreenAdminInfo.ACTIVATED)
74
+    except ScreenAdminInfo.DoesNotExist:
75
+        return response(PermissionStatusCode.PERMISSION_DENIED)
76
+
77
+    return response(200, {
78
+        'info': admin.data,
79
+    })

+ 12 - 0
page/templates/page/screen_admin_login_fail.html

@@ -0,0 +1,12 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+<head>
4
+    <meta charset="UTF-8">
5
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
7
+    <title>登录失败</title>
8
+</head>
9
+<body>
10
+    <div class="" style="text-align:center;margin-top:100px;font-size:25px;">登录失败</div>
11
+</body>
12
+</html>

+ 12 - 0
page/templates/page/screen_admin_login_success.html

@@ -0,0 +1,12 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+<head>
4
+    <meta charset="UTF-8">
5
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
7
+    <title>登录成功</title>
8
+</head>
9
+<body>
10
+    <div class="" style="text-align:center;margin-top:100px;font-size:25px;">登录成功</div>
11
+</body>
12
+</html>

+ 64 - 0
page/templates/page/screen_admin_oauth_qrcode.html

@@ -0,0 +1,64 @@
1
+{% load staticfiles %}
2
+
3
+<!DOCTYPE html>
4
+<html lang="zh-CN">
5
+    <head>
6
+        <meta charset="utf-8">
7
+        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
8
+        <meta name="format-detection" content="telephone=no,email=no,address=no">
9
+        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
10
+        <title>授权登录二维码</title>
11
+
12
+        <link href="//res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />
13
+
14
+        <style>
15
+            input:required:invalid {
16
+                color: #E64340;
17
+            }
18
+            input:required:valid {
19
+                color: rgb(0, 0, 0);
20
+            }
21
+            .hidden {
22
+                display: none;
23
+            }
24
+            .qr {
25
+                position: fixed;
26
+                left: 50%;
27
+                top: 50%;
28
+                margin-left: -100px;
29
+                margin-top: -100px;
30
+                padding: 5px 5px 0 5px;
31
+                border: 1px solid #000;
32
+                border-radius: 5px;
33
+            }
34
+        </style>
35
+    </head>
36
+    <body>
37
+        <div class="container" >
38
+            <img id="qr_logo" class="hidden" src="{% static 'kodo/img/paiai_96_96.png' %}">
39
+            <div id="qr" class="qr"></div>
40
+        </div>
41
+
42
+        <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
43
+        <script src="//cdnjs.cloudflare.com/ajax/libs/lrsjng.jquery-qrcode/0.14.0/jquery-qrcode.min.js"></script>
44
+        <script>
45
+            $("#qr").empty().qrcode({
46
+                render: 'canvas',
47
+                mode: 0,
48
+                text: '{{ qr }}'
49
+            });
50
+        </script>
51
+        <script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
52
+        <script type="text/javascript" src="{% static 'kodo/js/jswe-0.0.4.js' %}"></script>
53
+        <script>
54
+            V.initWxData({
55
+                imgUrl: "http://pai.ai/static/kodo/img/paiai_96_96.png",
56
+                link: 'http://pai.ai/w/o?r=http%3A%2F%2Fpai.ai%2Fp%2Floginqr',
57
+                desc: "授权登录",
58
+                title: "授权登录",
59
+                timeLine: ""
60
+            }, true);
61
+            V.hideOptionMenu();
62
+        </script>
63
+    </body>
64
+</html>

+ 13 - 0
page/templates/page/screen_admin_oauth_success.html

@@ -0,0 +1,13 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+<head>
4
+    <meta charset="UTF-8">
5
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
7
+    <title>授权成功</title>
8
+</head>
9
+<body>
10
+    <div class="" style="text-align:center;margin-top:100px;font-size:25px;">授权成功</div>
11
+    <div class="" style="text-align:center;font-size:15px;">请扫描统揽大屏二维码开启大屏</div>
12
+</body>
13
+</html>

+ 7 - 1
page/urls.py

@@ -4,7 +4,7 @@ from django.conf.urls import url
4 4
 
5 5
 from account import tourguide_views
6 6
 from group import lensman_views
7
-from page import info_views, oauth_views, page_views, sale_views
7
+from page import info_views, oauth_views, page_views, sale_views, screen_views
8 8
 
9 9
 
10 10
 urlpatterns = [
@@ -33,3 +33,9 @@ urlpatterns = [
33 33
     url(r'^clerk$', oauth_views.clerk_oauth, name='clerk_oauth'),  # 店员授权页面
34 34
     url(r'^clerk/info$', info_views.clerk_info_oauth, name='clerk_info_oauth'),  # 店员信息授权页面
35 35
 ]
36
+
37
+urlpatterns += [
38
+    url(r'^qr$', screen_views.screen_admin_oauthqr, name='oauthqr'),
39
+    url(r'^screen/admin/oauth$', screen_views.screen_admin_oauth, name='screen_admin_oauth'),
40
+    url(r'^screen/admin/login$', screen_views.screen_admin_login, name='screen_admin_login'),
41
+]

+ 1 - 1
requirements_dj.txt

@@ -2,7 +2,7 @@ Django==1.11.16
2 2
 django-admin==1.3.2
3 3
 django-cors-headers==2.4.0
4 4
 django-curtail-uuid==1.0.4
5
-django-detect==1.0.6
5
+django-detect==1.0.8
6 6
 django-file-md5==1.0.2
7 7
 django-file-upload==1.1.0
8 8
 django-ip==1.0.2

+ 5 - 0
utils/error/errno_utils.py

@@ -187,3 +187,8 @@ class TokenStatusCode(BaseStatusCode):
187 187
     """ 票据相关错误码 4090xx """
188 188
     TOKEN_NOT_FOUND = StatusCodeField(409901, 'Token Not Found', description=u'票据不存在')
189 189
     TOKEN_HAS_EXPIRED = StatusCodeField(409911, 'Token Has Expired', description=u'票据过期,请刷新重扫二维码')
190
+
191
+
192
+class PermissionStatusCode(BaseStatusCode):
193
+    """ 4099xx 权限相关错误码 """
194
+    PERMISSION_DENIED = StatusCodeField(409900, 'Permission Denied', description=u'权限不足')

+ 2 - 0
utils/redis/rkeys.py

@@ -69,3 +69,5 @@ BOX_PROGRAM_VERSION_INFO = 'box:program:version:info'  # STRING,BOX 程序版
69 69
 
70 70
 # 小程序相关
71 71
 MINI_PROGRAM_GIS_LIST = 'tamron:miniprogram:gis:list'
72
+
73
+KODO_SCREEN_ADMIN_LOGIN = 'kodo:screen:admin:login:%s:%s'  # brand_id, token